package com.haralabidis.jdeveloper.extension.subversionmonitor.util.svn;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNWCUtil;


public class SubversionHelper {

    SVNRepository repository = null;

    public class RevisionInfo {
        private String author;
        private Date date;
        private String log;
        private long revision;
        private List<ChangedPaths> changedPaths =
            new ArrayList<ChangedPaths>();

        public class ChangedPaths {
            private String path;
            private String type;

            public ChangedPaths(String path, char type) {
                this.path = path;
                this.type = Character.toString(type);
            }

            public String getPath() {
                return path;
            }

            public String getType() {
                return type;
            }
        }

        RevisionInfo(long revision, Date date, String author, String log) {
            this.revision = revision;
            this.date = date;
            this.author = author;
            this.log = log;
        }

        public String getAuthor() {
            return author;
        }

        public Date getDate() {
            return date;
        }

        public String getLog() {
            return log;
        }

        public long getRevision() {
            return revision;
        }

        public void setChangedPaths(List<SubversionHelper.RevisionInfo.ChangedPaths> changedPaths) {
            this.changedPaths = changedPaths;
        }

        public List<com.haralabidis.jdeveloper.extension.subversionmonitor.util.svn.SubversionHelper.RevisionInfo.ChangedPaths> getChangedPaths() {
            return changedPaths;
        }
    }

    public SubversionHelper() {
    }

    public boolean isAlive() {
        return (getRepositoryRoot().length() > 0);
    }

    public String getRepositoryRoot() {
        try {
            return repository.getRepositoryRoot(true).toString();
        } catch (SVNException e) {
            return "";
        } catch (Exception e) {
            return "";
        }
    }

    public List<RevisionInfo> getLogEntry(long startRevision,
                                          long endRevision) {

        List<RevisionInfo> revisions = new ArrayList<RevisionInfo>();

        try {
            Collection svnLogs =
                repository.log(new String[] { "" }, null, startRevision,
                               endRevision, true, true);

            SVNLogEntry[] entries =
                (SVNLogEntry[])svnLogs.toArray(new SVNLogEntry[svnLogs.size()]);

            for (int i = entries.length - 1; i >= 0; i--) {
                SVNLogEntry logEntry = entries[i];
                RevisionInfo revision =
                    new RevisionInfo(logEntry.getRevision(),
                                     logEntry.getDate(), logEntry.getAuthor(),
                                     (logEntry.getMessage() == null ||
                                      logEntry.getMessage().length() == 0) ?
                                     "<no changes log>" :
                                     logEntry.getMessage());

                if (logEntry.getChangedPaths().size() > 0) {
                    Set changedPathsSet = logEntry.getChangedPaths().keySet();

                    List<RevisionInfo.ChangedPaths> revisionPaths =
                        new ArrayList<RevisionInfo.ChangedPaths>();

                    for (Iterator changedPaths = changedPathsSet.iterator();
                         changedPaths.hasNext(); ) {
                        SVNLogEntryPath entryPath =
                            (SVNLogEntryPath)logEntry.getChangedPaths().get(changedPaths.next());

                        RevisionInfo.ChangedPaths revisionPath =
                            revision.new ChangedPaths(entryPath.getPath(),
                                                      entryPath.getType());

                        revision.changedPaths.add(revisionPath);
                    }
                }

                revisions.add(revision);
            }

        } catch (SVNException e) {
        }

        return revisions;
    }

    public long getLatestRevision() {
        try {
            return (repository != null) ? repository.getLatestRevision() : -1;
        } catch (SVNException e) {
            return -1;
        }
    }

    private void setup(String url) {
        if (url.startsWith("svn:")) {
            SVNRepositoryFactoryImpl.setup();

        } else if (url.startsWith("http:")) {
            DAVRepositoryFactory.setup();
        }
    }

    public void init(String url, String username, String password) {

        try {
            if (repository != null) {
                repository.closeSession();
            }

            setup(url);

            repository =
                    SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url));
            ISVNAuthenticationManager authManager =
                SVNWCUtil.createDefaultAuthenticationManager(username,
                                                             password);
            repository.setAuthenticationManager(authManager);
        } catch (SVNException e) {
            e.printStackTrace();
        }
    }
}
